<?php defined('SYSPATH') or die('No direct script access.');
/**
 * 支付宝支付 (标准双接口)
 *
 * 协议参数 [service] 说明：
 * create_direct_pay_by_user - 即时到账
 * create_partner_trade_by_buyer - 担保交易
 * trade_create_by_buyer - 标准双接口
 *
 * @author  Yellow.Chow <aultoale@gmail.com>
 * @version $Id: standard.php 93 2012-03-23 02:56:28Z yellow.chow $
 * @license http://www.gnu.org/licenses/gpl-3.0.html    GPL 3
 */
class Payment_Adapter_Alipay_Standard extends Payment_Adapter
{
    /**
     * 支付方式参数
     *
     * @var array
     */
    protected $_config = array(
        '_input_charset'    => 'utf-8', // 参数编码字符集
        'security_code'     => NULL, // 交易安全校验码
        /* 协议参数 */
        'service'           => 'trade_create_by_buyer', // 接口名称
        'partner'           => NULL, // 合作伙伴 ID，合作伙伴在支付宝的用户 ID (16个数字字符)
        'notify_url'        => NULL, // 状态通知 URL，交易状态同步通知接收的 URL
        'return_url'        => NULL, // 支付响应 URL，处理完成后返回的 URL
        'agent'             => NULL, // 代理商 ID，代理商在支付宝的用户 ID (16个数字字符)
        'sign_type'         => 'MD5',// 设定签名加密方式，(MD5/DSA) 目前仅支持 MD5
        /* 业务参数 */
        'subject'           => NULL, // 商名名称
        'body'              => NULL, // 商品描述
        'out_trade_no'      => NULL, // 外部交易号，格式：^[a-z0-9\-]{8,}$
        'price'             => NULL, // 商品单价
        'discount'          => NULL, // 折扣
        'show_url'          => NULL, // 商品展示网址
        'quantity'          => 1,    // 商品购买数量
        'payment_type'      => 1,    // 支付类型,
        /* 物流信息 */
        'logistics_type'    => NULL, // 物流类型，VIRTUAL：虚拟物品，POST：平邮,EMS，EXPRESS:其他快递公司
        'logistics_fee'     => NULL, // 物流费用
        'logistics_payment' => NULL, // 物流支付方式，SELLER_PAY：卖家支付,BUYER_PAY：买家支付，BUYER_PAY_AFTER_RECEIVE：货到付款
        'receive_name'      => NULL, // 收货人姓名
        'receive_address'   => NULL, // 收货人地址
        'receive_zip'       => NULL, // 收货人邮政编码
        'receive_phone'     => NULL, // 收货人电话号码
        'receive_mobile'    => NULL, // 收货人手机号码
        /* 卖方信息 */
        'seller_email'      => NULL, // 卖家的支付宝注册 Email
        'seller_id'         => NULL, // 卖家的支付宝注册 ID
        /* 买方信息 */
        'buyer_email'       => NULL, // 买家的支付宝注册 Email
        'buyer_id'          => NULL, // 买家的支付宝注册 ID
        'buyer_msg'         => NULL, // 买家留言
    );

    /**
     * 设置订单编号
     *
     * @param  string  $id
     * @return Payment_Adapter_Alipay
     */
    public function set_id($id)
    {
        $this->_config['out_trade_no'] = $id;

        return $this;
    }

    /**
     * 设置订单主题
     *
     * @param  string  $subject
     * @return Payment_Adapter_Alipay
     */
    public function set_subject($subject)
    {
        $this->_config['subject'] = $subject;

        return $this;
    }

    /**
     * 设置订单描述
     *
     * @param  string  $body
     * @return Payment_Adapter_Alipay
     */
    public function set_body($body)
    {
        $this->_config['body'] = $body;

        return $this;
    }

    /**
     * 设置订单总金额
     *
     * @param  float  $amount
     * @return Payment_Adapter
     */
    public function set_amount($amount)
    {
        $this->_config['price'] = $amount;
        $this->_config['quantity'] = 1;

        return $this;
    }

    /**
     * 设置安全校验码
     *
     * @param  string  $key
     * @return Payment_Adapter_Alipay
     */
    public function set_key($key)
    {
        $this->_config['security_code'] = $key;

        return $this;
    }

    /**
     * 获取支付网关地址
     *
     * @return string
     */
    public function get_gateway()
    {
        return 'https://www.alipay.com/cooperate/gateway.do';
    }

    /**
     * 获取基本参数
     *
     * @return array
     */
    protected function _get_params()
    {
        ksort($this->_config);
        reset($this->_config);

        $params = array();
        foreach ($this->_config as $key => $val)
        {
            if ($key != 'sign_type' AND $key != 'security_code' AND $val !== '' AND $val !== NULL)
            {
                $params[$key] = $val;
            }
        }

        return $params;
    }

    /**
     * 获取表单提交参数
     *
     * @return array
     */
    public function get_params()
    {
        return array_merge(
            $this->_get_params(),
            array(
                'sign' => $this->get_sign(),
                'sign_type' => 'MD5',
            )
        );
    }

    /**
     * 获取数字签名
     *
     * @return string
     */
    public function get_sign()
    {
        return md5(urldecode(http_build_query($this->_get_params())).$this->_config['security_code']);
    }

    /**
     * 获取支付 URL
     *
     * @return string
     */
    public function get_payurl()
    {
        return $this->get_gateway().'?'.http_build_query($this->get_params());
    }

    /**
     * 对参数进行校验
     *
     * @return bool
     */
    public function is_valid()
    {
        try
        {
            $config = $this->_config;

            // 字符集
            $config['_input_charset'] = strtolower($config['_input_charset']);
            if ($config['_input_charset'] != 'utf-8' AND $config['_input_charset'] != 'gbk')
            {
                throw new Payment_Exception('_input_charset：无效的参数编码字符集');
            }

            // 交易安全校验码
            if ( ! preg_match('/^[a-z0-9]{32}$/i', $config['security_code']))
            {
                throw new Payment_Exception('security_code：无效的安全校验码');
            }

            // 服务接口名称
            $config['service'] = strtolower($config['service']);

            // 合作伙伴 ID
            if ( ! preg_match('/^\d{16}$/', $config['partner']))
            {
                throw new Payment_Exception('partner：无效的合作伙伴 ID');
            }

            // 状态通知 URL
            if ( ! empty($config['notify_url']) AND ! Valid::url($config['notify_url']))
            {
                throw new Payment_Exception('notify_url：无效的状态通知 URL');
            }

            // 支付响应 URL
            if ( ! empty($config['return_url']) AND ! Valid::url($config['return_url']))
            {
                throw new Payment_Exception('return_url：无效的支付响应 URL');
            }

            // 代理商 ID
            if ( ! empty($config['agent']) AND ! preg_match('/\d{16}/', $config['agent']))
            {
                throw new Payment_Exception('agent：无效的代理商 ID');
            }

            // 签名加密方式
            $config['sign_type'] = strtoupper($config['sign_type']);
            if ($config['sign_type'] != 'MD5')
            {
                throw new Payment_Exception('sign_type：不支持的签名加密方式');
            }

            // 商品名称/订单主题
            $config['subject'] = Str::slice(trim(strip_tags($config['subject'])), 256);
            if (empty($config['subject']))
            {
                throw new Payment_Exception('subject：商品名称不能为空');
            }

            // 商品描述
            $config['body'] = Str::slice($config['body'], 400);

            // 外部交易号/订单编号
            if ( ! preg_match('/^[a-z0-9\-]{8,64}$/i', $config['out_trade_no']))
            {
                throw new Payment_Exception('out_trade_no：无效的订单编号');
            }

            // 商品单价/订单总金额
            if (floatval($config['price']) <= 0)
            {
                throw new Payment_Exception('price：无效的订单总金额');
            }

            // 折扣
            $config['discount'] = (float) number_format($config['discount'], 2, '.', '');
            if (floatval($config['discount']) < 0)
            {
                throw new Payment_Exception('discount：无效的商品折扣');
            }

            // 商品展示 URL
            if ( ! empty($config['show_url']) AND ! Valid::url($config['show_url']))
            {
                throw new Payment_Exception('show_url：无效的商品展示 URL');
            }

            // 商品购买数量
            if ($config['quantity'] < 1)
            {
                throw new Payment_Exception('quantity：商品购买数量不能小于 1');
            }

            // 支付类型
            if (empty($config['payment_type']))
            {
                throw new Payment_Exception('payment_type：支付类型不能为空');
            }
            if ( ! in_array($config['payment_type'], array('1', '2', '3', '4', '5', '6')))
            {
                throw new Payment_Exception('payment_type：无效的支付类型');
            }

            // 物流类型
            $config['logistics_type'] = strtoupper($config['logistics_type']);
            if (empty($config['logistics_type']))
            {
                throw new Payment_Exception('logistics_type：实物交易的物流类型不能为空');
            }
            if ( ! in_array($config['logistics_type'], array('VIRTUAL', 'POST', 'EMS', 'EXPRESS')))
            {
                throw new Payment_Exception('logistics_type：无效的物流类型');
            }

            // 物流费用
            $config['logistics_fee'] = (float) number_format($config['logistics_fee'], 2, '.', '');
            if (floatval($config['logistics_fee']) < 0) {
                throw new Payment_Exception('logistics_fee：无效的物流费用');
            }

            // 物流支付方式
            $config['logistics_payment'] = strtoupper($config['logistics_payment']);
            if (empty($config['logistics_payment']))
            {
                throw new Payment_Exception('logistics_payment：实物交易的物流支付方式不能为空');
            }
            if ( ! in_array($config['logistics_payment'], array('SELLER_PAY', 'BUYER_PAY', 'BUYER_PAY_AFTER_RECEIVE')))
            {
                throw new Payment_Exception('logistics_payment：无效的物流支付方式');
            }

            // 收货人姓名
            if ( ! empty($config['receive_name']) AND strlen($config['receive_name']) > 125) {
                throw new Payment_Exception('receive_name：收货人姓名不能大于 125 个字符');
            }

            // 收货人地址
            if ( ! empty($config['receive_address']) AND strlen($config['receive_address']) > 250)
            {
                throw new Payment_Exception('receive_address：收货人地址不能大于 250 个字符');
            }

            // 收货人邮政编码
            if ( ! empty($config['receive_zip']) AND ! Valid::postalcode($config['receive_zip']))
            {
                throw new Payment_Exception('receive_zip：无效的收货人邮政编码');
            }

            // 收货人电话号码
            if ( ! empty($config['receive_phone']) AND ! Valid::phone($config['receive_phone']))
            {
                throw new Payment_Exception('receive_phone：无效的收货人电话号码');
            }

            // 收货人手机号码
            if ( ! empty($config['receive_mobile']) AND ! Valid::phone($config['receive_mobile']))
            {
                throw new Payment_Exception('receive_mobile：无效的收货人手机号码');
            }

            // 卖家的支付宝注册 Email
            if ( ! empty($config['seller_email']) AND (strlen($config['seller_email']) > 100 OR ! Valid::email($config['seller_email'])))
            {
                throw new Payment_Exception('seller_email：无效的卖家支付宝注册 Email');
            }

            // 卖家的支付宝注册 ID
            if (strlen($config['seller_id']) > 30)
            {
                throw new Payment_Exception('seller_id：无效的卖家支付宝注册 ID');
            }

            // 卖家的支付宝注册 Email 或者 ID
            if (empty($config['seller_email']) AND empty($config['seller_id']))
            {
                throw new Payment_Exception('seller_email 或 seller_id 至少需要一个参数');
            }

            // 买家的支付宝注册 Email
            if ( ! empty($config['buyer_email']) AND (strlen($config['buyer_email']) > 100 OR ! Valid::email($config['buyer_email'])))
            {
                throw new Payment_Exception('buyer_email：无效的买家支付宝注册 Email');
            }

            // 卖家的支付宝注册 ID
            if (strlen($config['buyer_id']) > 30)
            {
                throw new Payment_Exception('buyer_id：无效的买家支付宝注册 ID');
            }

            // 买家留言
            $config['buyer_msg'] = Str::slice($config['buyer_msg'], 200);

            $this->_config = $config;

            return TRUE;
        }
        catch (Exception $e)
        {
            $this->_message = $e->getMessage();
            return FALSE;
        }
    }

    /**
     * 获取支付名称
     *
     * @return string
     */
    public function get_name()
    {
        return '支付宝';
    }
}